package com.atguigu.gmall.index.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @Author 刘嘉乐
 * @Date 2022/1/10 18:51
 * @Version 1.0
 */
@Component
//@Scope("prototype") //多例模式
public class DistributedLock {

    @Autowired
    private StringRedisTemplate redisTemplate;
    private Timer timer;

    public Boolean tryLock(String lockName, String uuid, Integer expire){
        String script = "if redis.call('exists', KEYS[1]) == 0 or redis.call('hexists', KEYS[1], ARGV[1]) == 1 " +
                "then " +
                "   redis.call('hincrby', KEYS[1], ARGV[1], 1) " +
                "   redis.call('expire', KEYS[1], ARGV[2]) " +
                "   return 1 " +
                "else " +
                "   return 0 " +
                "end";
        Boolean flag = this.redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),
                Arrays.asList(lockName), uuid, expire.toString());
          if (!flag){
              try {
                  Thread.sleep(50);
                  tryLock(lockName, uuid, expire);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }else {
              // 重置过期时间
              this.renewExpire(lockName, uuid, expire);
          }
          return true;
    }



    public void unlock(String lockName ,String uuid){
        String script = "if redis.call('hexists', KEYS[1], ARGV[1]) == 0 " +
                "then " +
                "   return nil " +
                "elseif redis.call('hincrby', KEYS[1], ARGV[1], -1) == 0 " +
                "then " +
                "   return redis.call('del', KEYS[1]) " +
                "else " +
                "   return 0 " +
                "end";
        Long flag = this.redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                Arrays.asList(lockName), uuid);
        if (flag==null){
            throw new RuntimeException("你要释放的锁不存在或者不属于你");

        }else if (flag==1){
            // 取消重置过期时间
            this.timer.cancel();
        }



    }


    private void renewExpire(String lockName, String uuid, Integer expire){
        String script = "if redis.call('hexists', KEYS[1], ARGV[1]) == 1 " +
                "then " +
                "   return redis.call('expire', KEYS[1], ARGV[2]) " +
                "else " +
                "   return 0 " +
                "end";
        this.timer = new Timer();
        this.timer.schedule(new TimerTask() {
            @Override
            public void run() {
            redisTemplate.execute(new DefaultRedisScript<>(script,Boolean.class),Arrays.asList(lockName),uuid,expire.toString());
            }
        },expire*1000/3,expire*1000/3);

    }

//                ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
          // schedule 一次性定时任务方法    scheduleAtFixedRate每隔定期时间执行一次
//        scheduledExecutorService.scheduleAtFixedRate(() -> {
//            System.out.println("这是定时任务线程池：" + System.currentTimeMillis());
//        }, 5, 10, TimeUnit.SECONDS);

}
